#pragma once
#include <string>
#include <vector>
#include <memory>
#include <cstdio>
using namespace std;

//一元运算符
enum class UnOp { Not, Neg };
//二元运算符
enum class BinOp {
    Add, Sub, Mul, Div, Mod,
    Eq, Neq, Lt, Le, Gt, Ge,
    And, Or
};

//表达式
class Expr {
public:
    virtual ~Expr() = default;
    virtual void print() const = 0;
};

//整数常量
class ENum : public Expr {
public:
    int value;
    ENum(int v) : value(v) {}
    void print() const override;
};

//标识符
class EId : public Expr {
public:
    string id;
    EId(const string& s) : id(s) {}
    void print() const override;
};

//一元运算
class EUnOp : public Expr {
public:
    UnOp op;
    unique_ptr<Expr> expr;
    EUnOp(UnOp o, Expr* e) : op(o), expr(e) {}
    void print() const override;
};

//二元运算
class EBinOp : public Expr {
public:
    BinOp op;
    unique_ptr<Expr> left;
    unique_ptr<Expr> right;
    EBinOp(BinOp o, Expr* l, Expr* r) : op(o), left(l), right(r) {}
    void print() const override;
};

//函数调用
class ECall : public Expr {
public:
    string id;
    vector<unique_ptr<Expr>> args;
    ECall(const string& s, vector<Expr*> a);
    void print() const override;
};

//语句
class Stmt {
public:
    virtual ~Stmt() = default;
    virtual void print() const = 0;
    virtual int countLocalVars() const = 0;
};

//语句表达式
class SExpr : public Stmt {
public:
    unique_ptr<Expr> expr;
    SExpr(Expr* e) : expr(e) {}
    void print() const override;
    int countLocalVars() const override;
};

//语句块
class SBlock : public Stmt {
public:
    vector<unique_ptr<Stmt>> stmts;
    SBlock(vector<Stmt*> s);
    void print() const override;
    int countLocalVars() const override;
};

class SIf : public Stmt {
public:
    unique_ptr<Expr> cond;
    unique_ptr<Stmt> thenStmt;
    unique_ptr<Stmt> elseStmt;
    SIf(Expr* c, Stmt* t, Stmt* e = nullptr);
    void print() const override;
    int countLocalVars() const override;
};

class SWhile : public Stmt {
public:
    unique_ptr<Expr> cond;
    unique_ptr<Stmt> body;
    SWhile(Expr* c, Stmt* b) : cond(c), body(b) {}
    void print() const override;
    int countLocalVars() const override;
};

class SReturn : public Stmt {
public:
    unique_ptr<Expr> expr;
    SReturn(Expr* e = nullptr) : expr(e) {}
    void print() const override;
    int countLocalVars() const override;
};

class SBreak : public Stmt {
public:
    void print() const override;
    int countLocalVars() const override;
};

class SContinue : public Stmt {
public:
    void print() const override;
    int countLocalVars() const override;
};

//变量声明
class SDecl : public Stmt {
public:
    string id;
    unique_ptr<Expr> expr;
    SDecl(const string& i, Expr* e) : id(i), expr(e) {}
    void print() const override;
    int countLocalVars() const override;
};

//赋值语句
class SAssign : public Stmt {
public:
    string id;
    unique_ptr<Expr> expr;
    SAssign(const string& i, Expr* e) : id(i), expr(e) {}
    void print() const override;
    int countLocalVars() const override;
};

enum class FuncType { TNum, TVoid };

//函数参数
struct Param {
    string id;
};

//函数定义
struct FuncDef {
    FuncType returnType;
    string name;
    vector<Param*> params;
    unique_ptr<Stmt> body;
    void print() const;
};

//编译单元
struct CompUnit {
    vector<unique_ptr<FuncDef>> funcs;
    explicit CompUnit(vector<FuncDef*> f);
    void print() const;
};

// 运算符转字符串
string stringOfUnOp(UnOp op);
string stringOfBinOp(BinOp op);
//表达式打印
void printExprOption(const unique_ptr<Expr>& expr);

// 根节点
extern CompUnit* g_comp_unit;